package com.lf.data;

import com.lf.connect.MongoDB;
import com.lf.web.service.KeyUpdate;
import com.mongodb.*;
import org.apache.log4j.Logger;
import org.bson.types.ObjectId;

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 严秋旺 on 2015/1/6.
 * 数据集操作DAO
 */
public abstract class CollectionDAO {

    private static final Logger LOGGER = Logger.getLogger(CollectionDAO.class);

    protected MongoDB nosql;
    private String collection;
    private WriteConcern writeConcern = WriteConcern.NORMAL;
    private String name = "";


    /**
     * @param nosql      数据库连接
     * @param collection 集合名称
     */
    public CollectionDAO(MongoDB nosql, String collection) {
        this.nosql = nosql;
        this.collection = collection;
    }

    public void setNosql(MongoDB nosql) throws UnknownHostException {
        nosql.init();
        this.nosql = nosql;
    }

    public MongoDB getNosql() {
        return nosql;
    }

    public DBCollection getCollection(String collection) {
        return this.getNosql().getCollection(collection);
    }

    public DBCollection getCollection() {
        return getCollection(collection);
    }

    public void setCollection(String collection) {
        this.collection = collection;
    }

    public String getName() {
        return name;
    }

    public WriteConcern getWriteConcern() {
        return writeConcern;
    }

    public void setWriteConcern(WriteConcern writeConcern) {
        this.writeConcern = writeConcern;
    }

    /**
     * 查询
     *
     * @param queryMap 搜索条件
     * @return 返回单个对象
     */
    public Cluster findOne(Cluster queryMap) {
        return findOne(queryMap, null);
    }

    /**
     * 查询
     *
     * @param queryMap 查询条件
     * @param fieldMap 查询列
     * @return 返回单个对象
     */
    public Cluster findOne(Cluster queryMap, Cluster fieldMap) {
        BasicDBObject query = null;
        BasicDBObject field = null;
        if (queryMap != null) {
            query = new BasicDBObject(queryMap);
        }
        if (fieldMap != null) {
            field = new BasicDBObject(fieldMap);
        }
        DBObject dbo = this.getCollection().findOne(query, field);
        if (dbo != null) {
            return new Cluster(dbo.toMap());
        } else {
            return new Cluster();
        }
    }

    /**
     * 查询
     *
     * @param querymap 查询条件
     * @param fieldmap 查询字段
     * @param sortmap  排序条件
     * @return 返回对象列表
     */
    public List<Cluster> find(Cluster querymap, Cluster fieldmap, Cluster sortmap) {
        BasicDBObject ref = null, field = null;
        if (querymap != null) {
            ref = new BasicDBObject(querymap);
        }
        if (fieldmap != null) {
            field = new BasicDBObject(fieldmap);
        }
        DBCursor dbcu = this.getCollection().find(ref, field);
        List<Cluster> list = new ArrayList<>();
        try {
            if (sortmap != null) {
                dbcu.sort(new BasicDBObject(sortmap));
            }
            while (dbcu.hasNext()) {
                list.add(new Cluster(dbcu.next().toMap()));
            }
        } catch (Exception e) {
            LOGGER.error(e);
        } finally {
            dbcu.close();
        }
        return list;
    }

    /**
     * 通过ID查询
     *
     * @param id 对象唯一id
     * @return 单个对象
     */
    public Cluster findById(String id) {
        BasicDBObject bdb = new BasicDBObject();
        bdb.put("_id", new ObjectId(id));
        DBObject dbo = this.getCollection().findOne(bdb);
        if (dbo != null) {
            return new Cluster(dbo.toMap());
        } else {
            return new Cluster();
        }
    }

    /**
     * 分页查询
     *
     * @param query 搜索条件
     * @param field 查询键
     * @param sort  排列键
     * @param page  分页对象
     * @return 返回包含分页信息与列表的Map
     */
    public Cluster findPage(Cluster query, Cluster field, Cluster sort, Page page) {
        BasicDBObject querybdb = null, fieldsbdb = null, sortbdb = null;
        if (query != null) {
            querybdb = new BasicDBObject(query);
        }
        if (field != null) {
            fieldsbdb = new BasicDBObject(field);
        }
        if (sort != null) {
            sortbdb = new BasicDBObject();
        }
        return findPage(querybdb, fieldsbdb, sortbdb, page);
    }

    protected Cluster findPage(BasicDBObject query, BasicDBObject fields, BasicDBObject sort, Page page) {
        DBCursor dbcu = this.getCollection().find(query, fields);
        Cluster map = new Cluster();
        try {
            if (sort != null) {
                dbcu.sort(sort);
            }
            dbcu.skip((page.getIndex() - 1) * page.getSize()).limit(page.getSize());
            List list = new ArrayList();
            while (dbcu.hasNext()) {
                list.add(dbcu.next().toMap());
            }
            page.setSum(dbcu.count());
            map.put(Global.PAGE, page);
            map.put(Global.PAGE_LIST, list);
        } catch (Exception e) {
            throw e;
        } finally {
            dbcu.close();
        }
        return map;
    }

    /**
     * 分页查询，但不查询总数
     *
     * @param querymap 查询条件
     * @param fieldmap 查询键
     * @param sortmap  排序键
     * @param page     分页对象
     * @return 查询列表
     */
    public List<Cluster> findList(Cluster querymap, Cluster fieldmap, Cluster sortmap, Page page) {
        BasicDBObject query = null, field = null, sort = null;
        if (querymap != null) {
            query = new BasicDBObject(querymap);
        }
        if (fieldmap != null) {
            field = new BasicDBObject(fieldmap);
        }
        if (sortmap != null) {
            sort = new BasicDBObject(sortmap);
        }
        DBCursor dbcu = this.getCollection().find(query, field);
        List list = new ArrayList();
        try {
            if (sort != null) {
                dbcu.sort(sort);
            }
            dbcu.skip((page.getIndex() - 1) * page.getSize()).limit(page.getSize());
            while (dbcu.hasNext()) {
                list.add(dbcu.next().toMap());
            }
        } finally {
            dbcu.close();
        }
        return list;
    }

    /**
     * 查询数量
     *
     * @param query 查询条件
     * @return 数量
     */
    public long count(Cluster query) {
        return this.getCollection().getCount(new BasicDBObject(query));
    }

    public int insert(Cluster data) {
        WriteResult wr = this.getCollection().insert(new BasicDBObject(data), this.getWriteConcern());
        if (wr.wasAcknowledged()) {
            return wr.getN();
        } else {
            return 0;
        }
    }

    public int insert(List<Cluster> datas) {
        List dbos = new ArrayList();
        for (Cluster cluster : datas) {
            dbos.add(new BasicDBObject(cluster));
        }
        WriteResult wr = this.getCollection().insert(dbos, this.getWriteConcern());
        if (wr.wasAcknowledged()) {
            return wr.getN();
        } else {
            return 0;
        }
    }

    /**
     * 将新数据替换数据库中的旧数据
     *
     * @param map 待保存的新数据
     * @return
     */
    public int save(Cluster map) {
        WriteResult wr = this.getCollection().save(new BasicDBObject(map), this.getWriteConcern());
        if (wr.wasAcknowledged()) {
            return wr.getN();
        } else {
            return 0;
        }
    }

    /**
     * 设置键值
     * 修改多行，不插入
     *
     * @param querymap  查询条件
     * @param updatemap 修改内容
     * @return
     */
    public int updateSet(Cluster querymap, Cluster updatemap) {
        Cluster update = null;
        if (updatemap != null) {
            update = new Cluster();
            update.put("$set", updatemap);
        }
        return update(querymap, update, false, true);
    }

    public int updateOne(Cluster querymap, Cluster updatemap) {
        return update(querymap, updatemap, false, false);
    }

    public int updateSetOne(Cluster querymap, Cluster updatemap) {
        Cluster update = null;
        if (updatemap != null) {
            update = new Cluster();
            update.put("$set", updatemap);
        }
        return updateOne(querymap, update);
    }

    public int update(KeyUpdate keyUpdate) throws Exception {
        Cluster queryMap = new Cluster();
        queryMap.put(Cluster.ID, new ObjectId(keyUpdate.getId()));
        Cluster updateMap = new Cluster();
        updateMap.put(keyUpdate.getKey(), keyUpdate.parseValue());
        return updateSetOne(queryMap, updateMap);
    }

    /**
     * 删除键
     *
     * @param querymap
     * @param updatemap
     * @return
     */
    public int updateUnset(Cluster querymap, Cluster updatemap) {
        Cluster update = null;
        if (updatemap != null) {
            update = new Cluster();
            update.put("$unset", updatemap);
        }
        return updateOne(querymap, update);
    }

    /**
     * 修改
     *
     * @param querymap  查询条件
     * @param updatemap 修改内容
     * @param upsert    是否插入
     * @param multil    是否修改多行
     * @return
     */
    public int update(Cluster querymap, Cluster updatemap, boolean upsert, boolean multil) {
        BasicDBObject query = null;
        BasicDBObject update = null;
        if (querymap != null) {
            query = new BasicDBObject(querymap);
        }
        if (updatemap != null) {
            update = new BasicDBObject(updatemap);
        }
        return update(query, update, upsert, multil);
    }

    protected int update(BasicDBObject query, BasicDBObject update, boolean upsert, boolean multil) {
        WriteResult wr = this.getCollection().update(query, update, upsert, multil, this.getWriteConcern());
        if (wr.wasAcknowledged()) {
            if (wr.wasAcknowledged()) {
                return wr.getN();
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    public int removeById(String id) {
        Cluster searhMap = new Cluster();
        searhMap.put(Cluster.ID, new ObjectId(id));
        return remove(searhMap);
    }

    public int remove(Cluster queryMap) {
        return this.remove(new BasicDBObject(queryMap));
    }

    protected int remove(BasicDBObject query) {
        WriteResult wr = getCollection().remove(query, this.getWriteConcern());
        if (wr.wasAcknowledged()) {
            return wr.getN();
        } else {
            return 0;
        }
    }

    protected boolean remove(BasicDBObject query, boolean purge) {
        DBObject dbo = getCollection().findAndRemove(query);
        getCollection("share").insert(dbo);
        return false;
    }

    public Map findAndRemove(Cluster querymap) {
        DBObject dbo = getCollection().findAndRemove(new BasicDBObject(querymap));
        if (dbo == null) {
            return new HashMap();
        } else {
            return dbo.toMap();
        }
    }
}
